package org.gcb.core.sandbox;

import java.util.Collection;
import java.util.logging.Logger;
import org.gcb.core.model.Armor;
import org.gcb.core.model.EArmorSlot;
import org.gcb.core.model.EWeaponSlot;
import org.gcb.core.model.Item;
import org.gcb.core.model.Toon;
import org.gcb.core.model.Weapon;
import org.openide.util.Lookup.Result;
import org.openide.util.LookupEvent;
import org.openide.util.NbBundle;
import org.openide.windows.TopComponent;
import org.openide.windows.WindowManager;
import org.openide.util.ImageUtilities;
import org.netbeans.api.settings.ConvertAsProperties;
import org.openide.util.Lookup;
import org.openide.util.LookupListener;

/**
 * Top component which displays something.
 */
@ConvertAsProperties(dtd = "-//org.gcb.core.sandbox//UISandbox//EN",
autostore = false)
public final class UISandboxTopComponent extends TopComponent implements LookupListener{

    private static UISandboxTopComponent instance;
    /** path to the icon used by the component and its open action */
    static final String ICON_PATH = "org/gcb/core/resources/lock.png";
    static final String DEFAULT_SLOT_ICON_PATH = "org/gcb/core/resources/Head.gif";
    private static final String PREFERRED_ID = "UISandboxTopComponent";
    private JSlot slotA;
    private JSlot slotB;
    private Lookup.Result<Toon> result = null;

    public UISandboxTopComponent() {
	slotA = new JSlot(DEFAULT_SLOT_ICON_PATH);//, new ToonSlotModel(slotA, null, EArmorSlot.ARMOR));
	slotB = new JSlot(DEFAULT_SLOT_ICON_PATH);//, new ToonSlotModel(slotB, null, EArmorSlot.ARMS));
	initComponents();
	setName(NbBundle.getMessage(UISandboxTopComponent.class, "CTL_UISandboxTopComponent"));
	setToolTipText(NbBundle.getMessage(UISandboxTopComponent.class, "HINT_UISandboxTopComponent"));
	setIcon(ImageUtilities.loadImage(ICON_PATH, true));
	slotA.setTransferHandler(new ItemToTransferSupport(EArmorSlot.ARMOR));
	slotB.setTransferHandler(new ItemToTransferSupport(EArmorSlot.ARMS));

	add(slotA);
	add(slotB);
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        setLayout(new java.awt.GridBagLayout());
    }// </editor-fold>//GEN-END:initComponents

    // Variables declaration - do not modify//GEN-BEGIN:variables
    // End of variables declaration//GEN-END:variables
    /**
     * Gets default instance. Do not use directly: reserved for *.settings files only,
     * i.e. deserialization routines; otherwise you could get a non-deserialized instance.
     * To obtain the singleton instance, use {@link #findInstance}.
     */
    public static synchronized UISandboxTopComponent getDefault() {
	if (instance == null) {
	    instance = new UISandboxTopComponent();
	}
	return instance;
    }

    /**
     * Obtain the UISandboxTopComponent instance. Never call {@link #getDefault} directly!
     */
    public static synchronized UISandboxTopComponent findInstance() {
	TopComponent win = WindowManager.getDefault().findTopComponent(PREFERRED_ID);
	if (win == null) {
	    Logger.getLogger(UISandboxTopComponent.class.getName()).warning(
		    "Cannot find " + PREFERRED_ID + " component. It will not be located properly in the window system.");
	    return getDefault();
	}
	if (win instanceof UISandboxTopComponent) {
	    return (UISandboxTopComponent) win;
	}
	Logger.getLogger(UISandboxTopComponent.class.getName()).warning(
		"There seem to be multiple components with the '" + PREFERRED_ID
		+ "' ID. That is a potential source of errors and unexpected behavior.");
	return getDefault();
    }

    @Override
    public int getPersistenceType() {
	return TopComponent.PERSISTENCE_ALWAYS;
    }

    @Override
    public void componentOpened() {
        result = WindowManager.getDefault().findTopComponent("ToonListingTopComponent").getLookup().lookupResult(Toon.class);
        result.addLookupListener(this);
        resultChanged(new LookupEvent(result));
    }

    @Override
    public void componentClosed() {
        result.removeLookupListener(this);
        result = null;
    }

    void writeProperties(java.util.Properties p) {
	// better to version settings since initial version as advocated at
	// http://wiki.apidesign.org/wiki/PropertyFiles
	p.setProperty("version", "1.0");
	// TODO store your settings
    }

    Object readProperties(java.util.Properties p) {
	if (instance == null) {
	    instance = this;
	}
	instance.readPropertiesImpl(p);
	return instance;
    }

    private void readPropertiesImpl(java.util.Properties p) {
	String version = p.getProperty("version");
	// TODO read your settings according to their version
    }

    @Override
    protected String preferredID() {
	return PREFERRED_ID;
    }

    @Override
    public void resultChanged(LookupEvent ev) {
	Lookup.Result r = (Result) ev.getSource();
	Collection<Toon> toons = r.allInstances();
	if (toons.isEmpty()) {
	    return;
	}
	Toon t = toons.iterator().next();

	slotA.setModel(new ToonSlotModel(slotA, t, EArmorSlot.ARMOR));
	slotB.setModel(new ToonSlotModel(slotB, t, EArmorSlot.ARMS));
    }

    private final class ToonSlotModel extends DefaultSlotModel<Item> {
	private JSlot jSlot;
	private Toon toon;
	private EArmorSlot armorSlot;
	private EWeaponSlot weaponSlot;
	private int slotType;

	public ToonSlotModel(JSlot slot, Toon toon, Item item) {
	    super(item);
	    init(slot, toon, null, null, 0);
	}

	public ToonSlotModel(JSlot slot, Toon toon, EArmorSlot armorSlot) {
	    init(slot, toon, armorSlot, null, 1);
	    if (toon!=null) {
		super.setItem(toon.getEquipment().getWorn().get(armorSlot));
	    }
	}

	public ToonSlotModel(JSlot slot, Toon toon, EWeaponSlot weaponSlot) {
	    init(slot, toon, null, weaponSlot, 2);
	    if (toon!=null) {
//		super.setItem(toon.getEquipment().getWorn().get(armorSlot));
	    }
	}

	private void init(JSlot slot, Toon toon, EArmorSlot armorSlot, EWeaponSlot weaponSlot, int slotType) {
	    this.jSlot = slot;
	    this.toon = toon;
	    this.armorSlot = armorSlot;
	    this.weaponSlot = weaponSlot;
	    this.slotType = slotType;
	}

	@Override
	public Item getItem() {
	    switch (slotType) {
		case 0:
		    return super.getItem();
		case 1:
		    return toon.getEquipment().getWorn().get(armorSlot);
		case 2:
		    throw new UnsupportedOperationException("Needs to be implemented");
//		    return toon.getEquipment().getWeapon().get(weaponSlot);
		default:
		    throw new IllegalArgumentException("Unknown slotType passed in. slotType="+slotType);
	    }
	}

	@Override
	public void setItem(Item item) {
	    Item oldItem = this.item;
	    this.item = item;
	    switch (slotType) {
		case 0:
		    break;
		case 1:
		    Armor armor = Armor.class.cast(item);
		    //XXXXX need to clean up code
		    if (item==null) {
			fireSlotUnequip();
		    } else {
			toon.getEquipment().getCarried().remove(item);
			if (toon.getEquipment().getWorn().isEmpty(armorSlot)) {
			    fireSlotEquip();
			} else {
			    toon.getEquipment().getCarried().add(toon.getEquipment().getWorn().get(armorSlot));
			    fireSlotSwap();
			}
		    }
		    toon.getEquipment().getWorn().put(armorSlot, armor);
		    break;
		case 2:
		    Weapon weapon = Weapon.class.cast(item);
		    //toon.getEquipment().getWeapon().put(weaponSlot, weapon);
		    throw new UnsupportedOperationException("Needs to be implemented");
//		    break;
		default:
		    throw new IllegalArgumentException("Unknown slotType passed in. slotType="+slotType);
	    }
	    super.setItem(item);
	    toon.getEquipment().getCarried().remove(item);
	    jSlot.setToolTipText(item.getDescription());
	}

	@Override
	public boolean isEmpty() {
	    switch (slotType) {
		case 0:
		    return super.isEmpty();
		case 1:
		    if (toon==null) {
			return super.isEmpty();
		    }
		    return toon.getEquipment().getWorn().isEmpty(armorSlot);
		case 2:
		    throw new UnsupportedOperationException("Needs to be implemented");
		default:
		    throw new IllegalArgumentException("Unknown slotType passed in. slotType="+slotType);
	    }
	}
    }
}